package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName : SpuServiceImpl  //类名
 * @Description :   //描述
 * @Author : qingfeng  //作者
 * @Date: 2020-09-18 10:50  //时间
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    private final BrandService brandService;
    private final CategoryService categoryService;
    private final SpuDetailService detailService;
    private final SkuService skuService;
    private final AmqpTemplate amqpTemplate;

    public SpuServiceImpl(BrandService brandService, CategoryService categoryService, SpuDetailService detailService, SkuService skuService, AmqpTemplate amqpTemplate) {
        this.brandService = brandService;
        this.categoryService = categoryService;
        this.detailService = detailService;
        this.skuService = skuService;
        this.amqpTemplate = amqpTemplate;
    }

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
        /**
         * @Description //TODO 分页查询
         * @Param [page, rows, saleable, categoryId, brandId, id]
         * @return com.leyou.common.dto.PageDTO<com.leyou.item.dto.SpuDTO>
         */
        //健壮性
        int current = Math.max(page, 1);
        int size = Math.max(rows,5);
        //2.准备查询条件，SELECT * FROM tb_spu WHERE saleable = ? AND category_id = ? AND brand_id = ? AND id = ?
        Page<Spu> result = query()
                .eq(saleable != null, "saleable", saleable)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(brandId != null, "brand_id", brandId)
                .eq(id != null, "id", id)
                //3.准备分页条件
                .page(new Page<>(current, size));
        //4.解析查询结果
        long total = result.getTotal();
        long pages = result.getPages();
        List<Spu> list = result.getRecords();
        //4.转换dto
        List<SpuDTO> dtoList = SpuDTO.convertEntityList(list);
        for (SpuDTO spuDTO : dtoList) {
            //查询spu的分类和品牌的名称
            handleCategoryAndBrandName(spuDTO);
        }
        //6.封装分页结果并返回
        return new PageDTO<>(total,pages,dtoList);
    }

    @Override
    public void saveGoods(SpuDTO spuDTO) {
        /**
         * @Description //TODO 新增商品
         * @Param [spuDTO]
         * @return void
         */
        //1.新增spu
        Spu spu = spuDTO.toEntity(Spu.class);
        spu.setSaleable(false);
        boolean success = save(spu);
        if (!success) {
            throw new LyException(500,"新增商品失败");
        }
        //2.新增spuDetail
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        success = detailService.save(spuDetail);
        if (!success){
            throw new LyException(500,"新增商品详情失败");
        }
        //3.新增sku
        List<Sku> list = spuDTO.getSkus().stream().map(skuDTO -> {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSaleable(false);
            sku.setSpuId(spu.getId());
            return sku;
        }).collect(Collectors.toList());
        //批量新增。
        skuService.saveBatch(list);
    }

    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        /**
         * @Description //TODO 修改上下架状态
         * @Param [id, saleable]
         * @return void
         */
        //1.更新spu
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);

        boolean success = updateById(spu);
        if (!success) {
            throw  new LyException(500,"更新失败");
        }
        //2.更新sku
        success = skuService.update().eq("spu_id", id).set("saleable", saleable).update();
        if (!success){
            throw new LyException(500,"更新失败");
        }
        //3 发送mq消息
        String routingKey =
                saleable ? MQConstants.RoutingKeyConstants.ITEM_UP_KEY : MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME,routingKey,id);
    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        /**
         * @Description //TODO 根据id查询商品
         * @Param [id]
         * @return com.leyou.item.dto.SpuDTO
         */
        //1.查询spu
        //1.1 查询
        Spu spu = getById(id);
        if (spu == null){
            throw new LyException(400,"商品id不存在");
        }
        //1.2 转换dto
        SpuDTO spuDTO = new SpuDTO(spu);
        //2 查询spudetail
        SpuDetail detail = detailService.getById(id);
        if (detail == null){
            throw new LyException(400,"商品id不存在!");
        }
        spuDTO.setSpuDetail(new SpuDetailDTO(detail));
        //3.查询sku
        List<Sku> list = skuService.query().eq("spu_id", id).list();
        if (CollectionUtils.isEmpty(list)){
            throw new LyException(400,"商品id不存在！");
        }
        spuDTO.setSkus(SkuDTO.convertEntityList(list));
        //4.准备商品分类和品牌名称
        handleCategoryAndBrandName(spuDTO);
        return spuDTO;
    }

    @Override
    public void updateGoods(SpuDTO spuDTO) {
        /**
         * @Description //TODO 更新商品
         * @Param [spuDTO]
         * @return void
         */
        //1.修改spu
        //1.1 判断是否存在spu的id，有说明需要修改，没有说明不需要
        Long spuId = spuDTO.getId();
        if (spuId != null) {
            //1.2 spu需要修改，更新spu，转换dto
            Spu spu = spuDTO.toEntity(Spu.class);
            //1.3 更新
            boolean success = updateById(spu);
            if (!success){
                //更新失败，抛出异常
                throw new LyException(500,"更新商品失败！");
            }
        }
        //2.修改spuDetail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        //2.1 判断是否为null
        if (detailDTO != null && detailDTO.getSpuId() != null){
            //2.2 spuDetail存在，需要修改，转换dto
            SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
            boolean success = detailService.updateById(detail);
            if (!success){
                //更新失败，抛出异常
                throw new LyException(500,"更新商品失败");
            }
        }
        //3 修改sku
        List<SkuDTO> dtoList = spuDTO.getSkus();
        //3.1 判断是否包含sku
        if (CollectionUtils.isEmpty(dtoList)){
            return;
        }
        //3.2 转换dto，并将sku根据saleable是否为空来分组，null是新增或修改，不是null是删除
        Map<Boolean, List<Sku>> map = dtoList.stream()
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));
        //3.3获取要新增或修改的sku
        List<Sku> insertOrUpdateList = map.get(true);
        //如果不为空，则修改或新增
        if (!CollectionUtils.isEmpty(insertOrUpdateList)){
            skuService.saveOrUpdateBatch(insertOrUpdateList);
        }
        //3.4 获取要删除的sku
        List<Sku> deleteSkuList = map.get(false);
        if (!CollectionUtils.isEmpty(deleteSkuList)){
            //存在要删除的sku
            List<Long> idList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            //删除
            skuService.removeByIds(idList);
        }
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
        //根据品牌id查询品牌名称
        Brand brand = brandService.getById(spuDTO.getBrandId());
        if (brand != null) {
            spuDTO.setBrandName(brand.getName());
        }
        //根据三级分类id查询分类集合
        List<Category> categories = categoryService.listByIds(spuDTO.getCategoryIds());
        if (!CollectionUtils.isEmpty(categories)) {
            String names = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
        }
    }
}
